added Feb 2001 SDK
[windows-sources.git] / shared source / sscli20 / jscript / engine / stringprototype.cs
blobac80bac1a0d87fbd105fcd79abbeca1fe990477b
1 // ==++==
2 //
3 //
4 // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
5 //
6 // The use and distribution terms for this software are contained in the file
7 // named license.txt, which can be found in the root of this distribution.
8 // By using this software in any fashion, you are agreeing to be bound by the
9 // terms of this license.
10 //
11 // You must not remove this notice, or any other, from this software.
12 //
13 //
14 // ==--==
16 namespace Microsoft.JScript{
18 using Microsoft.JScript.Vsa;
19 using System;
20 using System.Collections;
21 using System.Globalization;
22 using System.Text;
23 using System.Text.RegularExpressions;
25 public class StringPrototype : StringObject{
26 internal static readonly StringPrototype ob = new StringPrototype(FunctionPrototype.ob, ObjectPrototype.ob);
27 internal static StringConstructor _constructor;
29 internal StringPrototype(FunctionPrototype funcprot, ObjectPrototype parent)
30 : base(parent, ""){
31 this.noExpando = true;
34 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_anchor)]
35 public static String anchor(Object thisob, Object anchorName){
36 String thisStr = Convert.ToString(thisob);
37 String anchorStr = Convert.ToString(anchorName);
38 return "<A NAME=\""+anchorStr+"\">"+thisStr+"</A>";
41 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_big)]
42 public static String big(Object thisob){
43 return "<BIG>"+Convert.ToString(thisob)+"</BIG>";
46 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_blink)]
47 public static String blink(Object thisob){
48 return "<BLINK>"+Convert.ToString(thisob)+"</BLINK>";
51 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_bold)]
52 public static String bold(Object thisob){
53 return "<B>"+Convert.ToString(thisob)+"</B>";
56 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_charAt)]
57 public static String charAt(Object thisob, double pos){
58 String thisStr = Convert.ToString(thisob);
59 double position = Convert.ToInteger(pos);
60 if (position < 0 || !(position < thisStr.Length))
61 return "";
62 return thisStr.Substring((int)position, 1);
65 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_charCodeAt)]
66 public static Object charCodeAt(Object thisob, double pos){ //This returns an object so that integers stay integers
67 String thisStr = Convert.ToString(thisob);
68 double position = Convert.ToInteger(pos);
69 if (position < 0 || !(position < thisStr.Length))
70 return Double.NaN;
71 return (int)(thisStr[(int)position]);
74 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject|JSFunctionAttributeEnum.HasVarArgs, JSBuiltin.String_concat)]
75 public static String concat(Object thisob, params Object[] args){
76 StringBuilder concat = new StringBuilder(Convert.ToString(thisob));
77 for (int i = 0; i < args.Length; i++)
78 concat.Append(Convert.ToString(args[i]));
79 return concat.ToString();
82 public static StringConstructor constructor{
83 get{
84 return StringPrototype._constructor;
88 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_fixed)]
89 public static String @fixed(Object thisob){
90 return "<TT>"+Convert.ToString(thisob)+"</TT>";
93 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_fontcolor)]
94 public static String fontcolor(Object thisob, Object colorName){
95 String thisStr = Convert.ToString(thisob);
96 String colorStr = Convert.ToString(thisob);
97 return "<FONT COLOR=\""+colorStr+"\">"+thisStr+"</FONT>";
100 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_fontsize)]
101 public static String fontsize(Object thisob, Object fontSize){
102 String thisStr = Convert.ToString(thisob);
103 String fontStr = Convert.ToString(fontSize);
104 return "<FONT SIZE=\""+fontStr+"\">"+thisStr+"</FONT>";
107 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_indexOf)]
108 public static int indexOf(Object thisob, Object searchString, double position){
109 String thisStr = Convert.ToString(thisob);
110 String searchStr = Convert.ToString(searchString);
111 double startIndex = Convert.ToInteger(position);
112 int length = thisStr.Length;
113 if (startIndex < 0)
114 startIndex = 0;
115 if (startIndex >= length)
116 return searchStr.Length == 0 ? 0 : -1;
117 return thisStr.IndexOf(searchStr, (int)startIndex);
120 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_italics)]
121 public static String italics(Object thisob){
122 return "<I>"+Convert.ToString(thisob)+"</I>";
125 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_lastIndexOf)]
126 public static int lastIndexOf(Object thisob, Object searchString, double position){
127 String thisStr = Convert.ToString(thisob);
128 String searchStr = Convert.ToString(searchString);
129 int length = thisStr.Length;
130 int j = position != position || position > length ? length : (int)position;
131 if (j < 0)
132 j = 0;
133 if (j >= length)
134 j = length;
135 int slength = searchStr.Length;
136 if (slength == 0)
137 return j;
138 int k = j - 1 + slength;
139 if (k >= length)
140 k = length-1;
141 if (k < 0)
142 return -1;
143 return thisStr.LastIndexOf(searchStr, k);
146 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_link)]
147 public static String link(Object thisob, Object linkRef){
148 String thisStr = Convert.ToString(thisob);
149 String linkStr = Convert.ToString(linkRef);
150 return "<A HREF=\""+linkStr+"\">"+thisStr+"</A>";
153 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_localeCompare)]
154 public static int localeCompare(Object thisob, Object thatob){
155 return String.Compare(Convert.ToString(thisob), Convert.ToString(thatob), StringComparison.CurrentCulture);
158 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject|JSFunctionAttributeEnum.HasEngine, JSBuiltin.String_match)]
159 public static Object match(Object thisob, VsaEngine engine, Object regExp){
160 String thisStr = Convert.ToString(thisob);
161 RegExpObject regExpObject = StringPrototype.ToRegExpObject(regExp, engine);
162 Match match;
163 if (!regExpObject.globalInt){
164 match = regExpObject.regex.Match(thisStr);
165 if (!match.Success){
166 regExpObject.lastIndexInt = 0;
167 return DBNull.Value;
169 if (regExpObject.regExpConst != null){
170 regExpObject.lastIndexInt = regExpObject.regExpConst.UpdateConstructor(regExpObject.regex, match, thisStr);
171 return new RegExpMatch(regExpObject.regExpConst.arrayPrototype, regExpObject.regex, match, thisStr);
172 }else
173 return new RegExpMatch(engine.Globals.globalObject.originalRegExp.arrayPrototype, regExpObject.regex, match, thisStr);
175 MatchCollection matches = regExpObject.regex.Matches(thisStr);
176 if (matches.Count == 0){
177 regExpObject.lastIndexInt = 0;
178 return DBNull.Value;
180 match = matches[matches.Count - 1];
181 regExpObject.lastIndexInt = regExpObject.regExpConst.UpdateConstructor(regExpObject.regex, match, thisStr);
182 return new RegExpMatch(
183 regExpObject.regExpConst.arrayPrototype, regExpObject.regex, matches, thisStr);
186 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_replace)]
187 public static String replace(Object thisob, Object regExp, Object replacement){
188 String thisStr = Convert.ToString(thisob);
189 RegExpObject regExpObject = regExp as RegExpObject;
190 if (regExpObject != null) return StringPrototype.ReplaceWithRegExp(thisStr, regExpObject, replacement);
191 Regex regex = regExp as Regex;
192 if (regex != null) return StringPrototype.ReplaceWithRegExp(thisStr, new RegExpObject(regex), replacement);
193 return StringPrototype.ReplaceWithString(thisStr, Convert.ToString(regExp), Convert.ToString(replacement));
196 private static String ReplaceWithRegExp(String thisob, RegExpObject regExpObject, Object replacement){
197 RegExpReplace replacer = replacement is ScriptFunction
198 ? (RegExpReplace)(new ReplaceUsingFunction(regExpObject.regex, (ScriptFunction)replacement, thisob))
199 : (RegExpReplace)(new ReplaceWithString(Convert.ToString(replacement)));
200 MatchEvaluator matchEvaluator = new MatchEvaluator(replacer.Evaluate);
201 String newString = regExpObject.globalInt
202 ? regExpObject.regex.Replace(thisob, matchEvaluator)
203 : regExpObject.regex.Replace(thisob, matchEvaluator, 1);
204 regExpObject.lastIndexInt = replacer.lastMatch == null
206 : regExpObject.regExpConst.UpdateConstructor(regExpObject.regex, replacer.lastMatch, thisob);
207 return newString;
210 private static String ReplaceWithString(String thisob, String searchString, String replaceString){
211 int index = thisob.IndexOf(searchString);
212 if (index < 0)
213 return thisob;
214 StringBuilder newString = new StringBuilder(thisob.Substring(0, index));
215 newString.Append(replaceString);
216 newString.Append(thisob.Substring(index + searchString.Length));
217 return newString.ToString();
220 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject|JSFunctionAttributeEnum.HasEngine, JSBuiltin.String_search)]
221 public static int search(Object thisob, VsaEngine engine, Object regExp){
222 String thisStr = Convert.ToString(thisob);
223 RegExpObject regExpObject = StringPrototype.ToRegExpObject(regExp, engine);
224 Match match = regExpObject.regex.Match(thisStr);
225 if (!match.Success){
226 regExpObject.lastIndexInt = 0;
227 return -1;
229 regExpObject.lastIndexInt = regExpObject.regExpConst.UpdateConstructor(regExpObject.regex, match, thisStr);
230 return match.Index;
233 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_slice)]
234 public static String slice(Object thisob, double start, Object end){
235 String thisStr = Convert.ToString(thisob);
236 int length = thisStr.Length;
237 double startIndex = Convert.ToInteger(start);
238 double endIndex = (end == null || end is Missing)
239 ? length : Convert.ToInteger(end);
240 if (startIndex < 0){
241 startIndex = length + startIndex;
242 if (startIndex < 0)
243 startIndex = 0;
244 }else
245 if (startIndex > length)
246 startIndex = length;
247 if (endIndex < 0){
248 endIndex = length + endIndex;
249 if (endIndex < 0)
250 endIndex = 0;
251 }else
252 if (endIndex > length)
253 endIndex = length;
254 int nChars = (int)(endIndex - startIndex);
255 if (nChars <= 0)
256 return "";
257 else
258 return thisStr.Substring((int)startIndex, nChars);
261 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_small)]
262 public static String small(Object thisob){
263 return "<SMALL>"+Convert.ToString(thisob)+"</SMALL>";
266 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject|JSFunctionAttributeEnum.HasEngine, JSBuiltin.String_split)]
267 public static ArrayObject split(Object thisob, VsaEngine engine, Object separator, Object limit){
268 String thisStr = Convert.ToString(thisob);
269 uint limitValue = UInt32.MaxValue;
270 if (limit != null && !(limit is Missing) && limit != DBNull.Value){
271 double lmt = Convert.ToInteger(limit);
272 if (lmt >= 0 && lmt < UInt32.MaxValue)
273 limitValue = (uint)lmt;
275 if (limitValue == 0)
276 return (ArrayObject)engine.GetOriginalArrayConstructor().Construct();
277 if (separator == null || separator is Missing){
278 ArrayObject array = (ArrayObject)engine.GetOriginalArrayConstructor().Construct();
279 array.SetValueAtIndex(0, thisob);
280 return array;
282 RegExpObject regExpObject = separator as RegExpObject;
283 if (regExpObject != null) return StringPrototype.SplitWithRegExp(thisStr, engine, regExpObject, limitValue);
284 Regex regex = separator as Regex;
285 if (regex != null) return StringPrototype.SplitWithRegExp(thisStr, engine, new RegExpObject(regex), limitValue);
286 return StringPrototype.SplitWithString(thisStr, engine, Convert.ToString(separator), limitValue);
289 private static ArrayObject SplitWithRegExp(String thisob, VsaEngine engine, RegExpObject regExpObject, uint limit){
290 ArrayObject array = (ArrayObject)engine.GetOriginalArrayConstructor().Construct();
291 Match match = regExpObject.regex.Match(thisob);
293 if (!match.Success){
294 array.SetValueAtIndex(0, thisob);
295 regExpObject.lastIndexInt = 0;
296 return array;
300 Match lastMatch;
301 int prevIndex = 0;
302 uint i = 0;
305 int len = match.Index - prevIndex;
306 if (len > 0)
308 array.SetValueAtIndex(i++, thisob.Substring(prevIndex, len));
309 if (limit > 0 && i >= limit){
310 regExpObject.lastIndexInt = regExpObject.regExpConst.UpdateConstructor(regExpObject.regex, match, thisob);
311 return array;
316 prevIndex = match.Index + match.Length;
317 lastMatch = match;
318 match = match.NextMatch();
319 }while(match.Success);
321 if (prevIndex < thisob.Length)
322 array.SetValueAtIndex(i, thisob.Substring(prevIndex));
323 regExpObject.lastIndexInt = regExpObject.regExpConst.UpdateConstructor(regExpObject.regex, lastMatch, thisob);
325 return array;
328 private static ArrayObject SplitWithString(String thisob, VsaEngine engine, String separator, uint limit){
329 ArrayObject array = (ArrayObject)engine.GetOriginalArrayConstructor().Construct();
330 if (separator.Length == 0){
331 if (limit > thisob.Length)
332 limit = (uint)thisob.Length;
333 for (int i = 0; i < limit; i++)
334 array.SetValueAtIndex((uint)i, thisob[i].ToString());
335 }else{
336 int prevIndex = 0;
337 uint i = 0;
338 int index;
339 while ((index = thisob.IndexOf(separator, prevIndex)) >= 0){
340 array.SetValueAtIndex(i++, thisob.Substring(prevIndex, index-prevIndex));
341 if (i >= limit)
342 return array;
343 prevIndex = index + separator.Length;
345 if (i == 0)
346 array.SetValueAtIndex(0, thisob);
347 else
348 array.SetValueAtIndex(i, thisob.Substring(prevIndex));
350 return array;
353 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_strike)]
354 public static String strike(Object thisob){
355 return "<STRIKE>"+Convert.ToString(thisob)+"</STRIKE>";
358 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_sub)]
359 public static String sub(Object thisob){
360 return "<SUB>"+Convert.ToString(thisob)+"</SUB>";
363 [NotRecommended("substr")]
364 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_substr)]
365 public static String substr(Object thisob, double start, Object count){
366 String thisStr = thisob as String;
367 if (thisStr == null) thisStr = Convert.ToString(thisob);
368 int length = thisStr.Length;
369 double startIndex = Convert.ToInteger(start);
370 if (startIndex < 0)
371 startIndex += length;
372 if (startIndex < 0)
373 startIndex = 0;
374 else if (startIndex > length)
375 startIndex = length;
376 int nChars = count is int ? (int)count :
377 ((count == null || count is Missing) ? length-(int)Runtime.DoubleToInt64(startIndex) : (int)Runtime.DoubleToInt64(Convert.ToInteger(count)));
378 if (startIndex+nChars > length)
379 nChars = length - (int)startIndex;
380 if (nChars <= 0)
381 return "";
382 else
383 return thisStr.Substring((int)startIndex, nChars);
386 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_substring)]
387 public static String substring(Object thisob, double start, Object end){
388 String thisStr = thisob as String;
389 if (thisStr == null) thisStr = Convert.ToString(thisob);
390 int length = thisStr.Length;
391 double startIndex = Convert.ToInteger(start);
392 if (startIndex < 0)
393 startIndex = 0;
394 else if (startIndex > length)
395 startIndex = length;
396 double endIndex = (end == null || end is Missing)
397 ? length : Convert.ToInteger(end);
398 if (endIndex < 0)
399 endIndex = 0;
400 else if (endIndex > length)
401 endIndex = length;
402 if (startIndex > endIndex){
403 double temp = startIndex;
404 startIndex = endIndex;
405 endIndex = temp;
407 return thisStr.Substring((int)startIndex, (int)(endIndex - startIndex));
410 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_sup)]
411 public static String sup(Object thisob){
412 return "<SUP>"+Convert.ToString(thisob)+"</SUP>";
415 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_toLocaleLowerCase)]
416 public static String toLocaleLowerCase(Object thisob){
417 return Convert.ToString(thisob).ToLower(CultureInfo.CurrentUICulture);
420 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_toLocaleUpperCase)]
421 public static String toLocaleUpperCase(Object thisob){
422 return Convert.ToString(thisob).ToUpperInvariant();
425 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_toLowerCase)]
426 public static String toLowerCase(Object thisob){
427 return Convert.ToString(thisob).ToLowerInvariant();
430 private static RegExpObject ToRegExpObject(Object regExp, VsaEngine engine){
431 if (regExp == null || regExp is Missing)
432 return (RegExpObject)engine.GetOriginalRegExpConstructor().Construct("", false, false, false);
433 RegExpObject result = regExp as RegExpObject;
434 if (result != null) return result;
435 Regex regex = regExp as Regex;
436 if (regex != null) return new RegExpObject(regex);
437 return (RegExpObject)engine.GetOriginalRegExpConstructor().Construct(Convert.ToString(regExp), false, false, false);
440 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_toString)]
441 public static String toString(Object thisob){
442 StringObject strob = thisob as StringObject;
443 if (strob != null) return strob.value;
444 ConcatString concatStr = thisob as ConcatString;
445 if (concatStr != null) return concatStr.ToString();
446 IConvertible ic = Convert.GetIConvertible(thisob);
447 if (Convert.GetTypeCode(thisob, ic) == TypeCode.String) return ic.ToString(null);
448 throw new JScriptException(JSError.StringExpected);
451 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_toUpperCase)]
452 public static String toUpperCase(Object thisob){
453 return Convert.ToString(thisob).ToUpperInvariant();
456 [JSFunctionAttribute(JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_valueOf)]
457 public static Object valueOf(Object thisob){
458 return StringPrototype.toString(thisob);